<template>
  <el-card class="box-card">
    <!-- 校验表单 -->
    <el-form ref="spu" :model="spu" :rules="rules" label-width="80px">
      <!-- SPU名称 -->
      <el-form-item prop="spuName" label="SPU名称">
        <el-input v-model="spu.spuName" placeholder="请输入SPU名称" />
      </el-form-item>
      <!-- SPU品牌 -->
      <el-form-item prop="tmId" label="SPU品牌">
        <el-select v-model="spu.tmId" placeholder="请输入SPU品牌">
          <el-option
            v-for="trademark in trademarkList"
            :key="trademark.id"
            :value="trademark.id"
            :label="trademark.tmName"
          />
        </el-select>
      </el-form-item>
      <!-- SPU描述 -->
      <el-form-item prop="description" label="SPU描述">
        <el-input
          v-model="spu.description"
          type="textarea"
          placeholder="请输入SPU描述"
        />
      </el-form-item>
      <!-- SPU图片 -->
      <!--
        class:上传达到最大数量时隐藏上传框
        accept:接受上传的文件类型
        limit:最大允许上传个数
        action:上传地址
        list-type:文件列表类型
        file-list:上传的文件列表
        before-upload:文件上传前触发
        on-success:文件上传成功触发
        on-preview:点击预览触发
        on-remove：点击移除触发
       -->
      <el-form-item prop="spuImageList" label="SPU图片">
        <el-upload
          :class="{ 'spu-upload': spu.spuImageList.length >= limit }"
          accept="image/jpeg,image/jpg,image/png"
          :limit="limit"
          :action="interceptUrl + '/admin/product/fileUpload'"
          list-type="picture-card"
          :file-list="fileSpuImageList"
          :before-upload="beforeAvatarUpload"
          :on-success="handleAvatarSuccess"
          :on-preview="handlePictureCardPreview"
          :on-remove="handleRemove"
        >
          <i class="el-icon-plus" />
          <div slot="tip" class="el-upload__tip">
            只能上传jpg/png文件，且不超过500kb
          </div>
        </el-upload>
        <el-dialog
          :visible.sync="dialogVisible"
          class="spu-dialog"
          width="440px"
        >
          <!-- eslint-disable-next-line -->
          <img width="400px" :src="dialogImageUrl" alt="" />
        </el-dialog>
      </el-form-item>
      <!-- 销售属性 -->
      <el-form-item label="销售属性">
        <el-select
          v-model="saleAttr"
          :placeholder="`还剩${filterBaseSaleAttrList.length}个销售属性`"
        >
          <el-option
            v-for="baseSaleAttr in filterBaseSaleAttrList"
            :key="baseSaleAttr.id"
            :value="baseSaleAttr.name"
            :label="baseSaleAttr.name"
          />
        </el-select>
        <el-button
          type="primary"
          icon="el-icon-plus"
          :disabled="!saleAttr"
          @click="handleAddSaleAttrValue()"
          >添加销售属性值</el-button
        >
      </el-form-item>
      <!-- 销售属性列表 -->
      <el-form-item prop="spuSaleAttrList">
        <el-table :data="spu.spuSaleAttrList" border style="width: 100%">
          <el-table-column
            type="index"
            align="center"
            label="序号"
            width="50px"
          />
          <el-table-column
            prop="saleAttrName"
            align="center"
            label="属性名"
            width="150px"
          />
          <!-- scope:{
            row, 当前行数据
            $index 序号
          } -->
          <el-table-column
            v-slot="{ row, $index }"
            label="属性值列表"
            align="center"
          >
            <el-tag
              v-for="(spuSaleAttrValue, index) in row.spuSaleAttrValueList"
              :key="index"
              class="sale-value-tag"
              closable
              size="mini"
              @close="handleTagClose(row, index)"
            >
              {{ spuSaleAttrValue.saleAttrValueName }}
            </el-tag>
            <el-button
              v-show="!row.isEdit"
              icon="el-icon-plus"
              size="mini"
              @click="handleSaleAttrValueEdit(row, $index)"
              >添加属性值</el-button
            >
            <el-input
              :ref="$index"
              v-show="row.isEdit"
              v-model="saleAttrValueName"
              class="sale-value-input"
              placeholder="请输入属性值"
              size="mini"
              @blur="handleAddSaleAttrValueName(row)"
            />
          </el-table-column>
          <el-table-column
            v-slot="{ row, $index }"
            label="操作"
            align="center"
            width="150px"
          >
            <el-tooltip
              slot="reference"
              effect="dark"
              content="删除销售属性"
              placement="top"
            >
              <el-button
                icon="el-icon-delete"
                type="danger"
                size="mini"
                @click="handleDelSpuSaleAttr($index)"
              />
            </el-tooltip>
          </el-table-column>
        </el-table>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handlerSaveSpuInfo">确定</el-button>
        <el-button @click="$emit('isShow', 1)">取消</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script>
import { mapState } from 'vuex'
import { reqGetTrademarkList } from '@/api/product/trademark'
import {
  reqGetBaseSaleAttrList,
  reqSaveSpuInfo,
  reqGetSpuImageList,
  reqGetSpuSaleAttrList,
  reqUpdateSpuInfo
} from '@/api/product/spu'

export default {
  name: 'SaveSpu',
  props: {
    // 修改spu属性时接收的数据
    editSpu: {
      type: Object
    }
  },
  data() {
    // 自定义校验规则
    const spuImageListValidator = (rule, value, callback) => {
      if (value.length) {
        callback()
      } else {
        callback('请至少上传一张SPU图片')
      }
    }
    const spuSaleAttrListValidator = (rule, value, callback) => {
      if (!value.length) {
        callback('请添加至少一个销售属性')
      }
      const isAllHaveAttrValue = value.every(spuSaleAttr => {
        return spuSaleAttr.spuSaleAttrValueList.length
      })
      if (!isAllHaveAttrValue) {
        callback('请为每一个销售属性添加至少一个属性值')
      }
      callback()
    }
    return {
      // 图片预览展示图片地址
      dialogImageUrl: '',
      // 图片预览框是否开启
      dialogVisible: false,
      // 选中的销售属性
      saleAttr: '',
      // 品牌id
      spuId: '',
      // 要校验的数据
      spu: {
        // Spu名称
        spuName: '',
        // Spu品牌
        tmId: '',
        // Spu描述
        description: '',
        // Spu图片列表
        spuImageList: [],
        // spuImageList: [{ imgName: '', imgUrl: '' }],
        // Spu销售属性列表
        spuSaleAttrList: [],
        // spuSaleAttrList: [
        //   {
        //     saleAttrName: '',
        //     baseSaleAttrId:'',
        //     spuSaleAttrValueList: [{ saleAttrValueName: '',baseSaleAttrId:'', }]
        //   }
        // ]
        ...this.editSpu
      },
      // 校验规则
      rules: {
        spuName: [
          { required: true, message: '请输入SPU名称', trigger: 'blur' }
        ],
        tmId: [{ required: true, message: '请选择SPU品牌' }],
        description: [
          { required: true, message: '请输入SPU描述', trigger: 'blur' }
        ],
        spuImageList: [{ required: true, validator: spuImageListValidator }],
        spuSaleAttrList: [
          {
            required: true,
            validator: spuSaleAttrListValidator
          }
        ]
      },
      // spu品牌列表
      trademarkList: [],
      // 销售属性列表
      baseSaleAttrList: [],
      // 上传头像需要的代理服务器拦截路径
      interceptUrl: process.env.VUE_APP_BASE_API,
      // 上传图片允许最大个数
      limit: 5,
      // 属性值列表中输入框的值
      saleAttrValueName: ''
    }
  },
  computed: {
    ...mapState('category', ['category3Id']),
    // 销售属性值根据销售属性列表动态变化,使用filter可以不该变原数组，
    // 每次变化后不影响显示的顺序
    filterBaseSaleAttrList() {
      return this.baseSaleAttrList.filter(baseSaleAttr => {
        return this.spu.spuSaleAttrList.every(spuSaleAttr => {
          return spuSaleAttr.saleAttrName !== baseSaleAttr.name
        })
      })
    },
    // 接收spu图片列表数据，转化为el-elment组件el-upload允许的变量
    fileSpuImageList() {
      return this.spu.spuImageList.map(spuImage => {
        return (spuImage = {
          name: spuImage.imgName,
          url: spuImage.imgUrl,
          // 稳定不变的uid属性可以避免图片上传出现晃动
          uid: spuImage.id
        })
      })
    }
  },
  async mounted() {
    // const trademarkListRespond = await reqGetTrademarkList()
    // const baseSaleAttrListRespond = await reqGetBaseSaleAttrList()
    // this.trademarkList = trademarkListRespond.data
    // this.baseSaleAttrList = baseSaleAttrListRespond.data
    /* 需要同时发送两个请求并获取返回数据，使用Promise中的all方法，all方法传入一个数组，
     * 数组中元素为promise对象，只有promise对象返回状态都为成功时all方法返回成功，
     * 否则返回失败
     */
    let promise = [reqGetTrademarkList(), reqGetBaseSaleAttrList()]
    const { id } = this.spu
    // 若是修改spu，则组件从父组件接收到的数据中会含有id，需要发送请求获取图片和销售属性
    if (id) {
      promise = promise.concat([
        reqGetSpuImageList(id),
        reqGetSpuSaleAttrList(id)
      ])
    }
    try {
      const [
        trademarkListRespond,
        baseSaleAttrListRespond,
        spuImageListRespond,
        spuSaleAttrListRespond
      ] = await Promise.all(promise)
      this.trademarkList = trademarkListRespond.data
      this.baseSaleAttrList = baseSaleAttrListRespond.data
      if (spuImageListRespond) {
        console.log(spuSaleAttrListRespond.data)
        this.spu.spuImageList = spuImageListRespond.data
        this.spu.spuSaleAttrList = spuSaleAttrListRespond.data
      }
    } catch (e) {
      this.$message({ type: 'error', message: '获取数据失败' })
    }
  },
  methods: {
    // 删除图片后清除该图片数据
    handleRemove(file, fileList) {
      this.spu.spuImageList = this.spu.spuImageList.filter(spuImage => {
        return spuImage.imgUrl !== file.url
      })
    },
    // 图片预览
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url
      this.dialogVisible = true
    },
    // 上传图片前校验图片类型和大小
    beforeAvatarUpload(file) {
      // 允许图片类型jpeg，png，jpg
      const imgType = ['image/jpeg', 'image/png', 'image/jpg']
      const isType = imgType.includes(file.type)
      // 允许图片大小不超过500kb
      const isLt500K = file.size / 1024 < 500
      if (!isType) {
        this.$message.error('上传头像图片只能是 JPG，PNG，JPEG 格式!')
      }
      if (!isLt500K) {
        this.$message.error('上传头像图片大小不能超过 500KB!')
      }
      return isType && isLt500K
    },
    // 上传图片成功后获取图片url并清除校验结果
    handleAvatarSuccess(res, file) {
      // this.imageUrl = res.data
      this.spu.spuImageList.push({
        imgName: file.name,
        imgUrl: res.data,
        // id属性为了保证computed中fileSpuImageList的uid属性有稳定的值
        id: file.uid
      })
      this.$refs.spu.clearValidate('spuImageList')
    },
    // 添加销售属性值
    handleAddSaleAttrValue() {
      this.spu.spuSaleAttrList.push({
        saleAttrName: this.saleAttr,
        spuSaleAttrValueList: [],
        // 属性值列表是否是编辑状态
        // isEdit: false,
        // 基础销售属性值id，不传亦可上传成功，但是无法发送请求获取到销售属性列表数据
        baseSaleAttrId: this.baseSaleAttrList.find(baseSaleAttr => {
          return baseSaleAttr.name === this.saleAttr
        }).id
      })
      this.saleAttr = ''
    },
    // 删除销售属性列表中的销售属性
    handleDelSpuSaleAttr(index) {
      this.spu.spuSaleAttrList.splice(index, 1)
    },
    // 点击添加属性值按钮并自动聚焦
    handleSaleAttrValueEdit(row, index) {
      // row.isEdit = true
      // 修改spu时从父组件获取的数据中没有isEdit属性，为了保证点击按钮自动聚焦输入框，
      // 需要给数据添加响应式的isEdit属性
      this.$set(row, 'isEdit', true)
      this.$nextTick(() => {
        this.$refs[index].focus()
      })
    },
    // 输入框失去焦点时添加销售属性的属性值
    handleAddSaleAttrValueName(row) {
      const { saleAttrValueName } = this
      if (saleAttrValueName) {
        row.spuSaleAttrValueList.push({
          // 属性值
          saleAttrValueName,
          // 基础销售属性值id，不传亦可上传成功，但是无法发送请求获取到销售属性列表数据
          baseSaleAttrId: row.baseSaleAttrId
        })
        this.saleAttrValueName = ''
      }
      row.isEdit = false
    },
    // 删除属性值标签
    handleTagClose(row, index) {
      row.spuSaleAttrValueList.splice(index, 1)
    },
    // 确认添加SPU属性
    handlerSaveSpuInfo() {
      // validate中必须传入一个回调函数，否则校验会报错
      this.$refs.spu.validate(async value => {
        const { spu, category3Id } = this
        if (value) {
          // 判断有无id值，有id值则id是由父组件传入，此时是修改spu属性，发送更新请求，
          // 否则则为添加spu属性，发送添加请求
          if (spu.id) {
            await reqUpdateSpuInfo({ ...spu, category3Id })
          } else {
            await reqSaveSpuInfo({ ...spu, category3Id })
          }
          this.$message({
            type: 'success',
            message: `${spu.id ? '修改' : '添加'}spu属性成功`
          })
          this.$emit('isShow', 1)
        }
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.sale-value-input {
  width: 150px;
}
.sale-value-tag {
  margin-right: 10px;
}
</style>
